package com.tyk.bookstore.back.message.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tyk.bookstore.back.common.core.model.result.CommonResultEnum;
import com.tyk.bookstore.back.common.core.util.AssertUtil;
import com.tyk.bookstore.back.common.core.util.IdGenerator;
import com.tyk.bookstore.back.common.core.util.ObjUtil;
import com.tyk.bookstore.back.common.mq.RabbitManager;
import com.tyk.bookstore.back.common.security.util.SecurityUtil;
import com.tyk.bookstore.back.message.model.entity.ServiceNoticeDo;
import com.tyk.bookstore.back.message.model.enume.NoticeState;
import com.tyk.bookstore.back.message.model.query.ServiceNoticeAddQuery;
import com.tyk.bookstore.back.message.model.query.ServiceNoticePageQuery;
import com.tyk.bookstore.back.message.model.query.ServiceNoticeUpdateQuery;
import com.tyk.bookstore.back.message.model.result.ServiceNoticeResultEnum;
import com.tyk.bookstore.back.message.model.vo.ServiceNoticePageVo;
import com.tyk.bookstore.back.message.model.vo.ServiceNoticeVo;
import com.tyk.bookstore.back.message.mq.NoticeMqConstant;
import com.tyk.bookstore.back.message.repository.ServiceNoticeRepository;
import com.tyk.bookstore.back.message.service.ServiceNoticeService;
import com.tyk.bookstore.back.message.util.MapStructMessage;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.awt.print.Book;
import java.time.Duration;
import java.time.LocalDateTime;

/**
 * @author tyk
 * @description 服务通知管理
 */
@Service
@RequiredArgsConstructor
public class ServiceNoticeServiceImp implements ServiceNoticeService {
    private final ServiceNoticeRepository serviceNoticeRepository;
    private final MapStructMessage mapStructMessage;
    private final RabbitManager rabbitManager;

    @Override
    public ServiceNoticeVo getById(Long id) {
        ServiceNoticeDo notice = serviceNoticeRepository.selectById(id);
        AssertUtil.notNull(notice, ServiceNoticeResultEnum.NOTICE_NOT_FOUND);
        return mapStructMessage.toServiceNoticeVo(notice);
    }

    @Override
    public ServiceNoticePageVo getPage(ServiceNoticePageQuery query) {
        Page<ServiceNoticeDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<ServiceNoticeDo> w = buildPageQueryWrapper(query);
        serviceNoticeRepository.selectPage(page, w);
        return mapStructMessage.toServiceNoticePageVo(page);
    }


    @Override
    public void add(ServiceNoticeAddQuery query) {

        long userId = SecurityUtil.getLoginId();

        // 关联字段校验
        boolean f = ObjUtil.equal(query.getState(), NoticeState.ON) && ObjUtil.equal(query.getTimedRelease(), true);
        if (f) {
            AssertUtil.notNull(query.getReleaseTime(), CommonResultEnum.PARAM_ERROR);
            query.setState(NoticeState.OFF);
        }

        // 插入数据库
        ServiceNoticeDo snd = mapStructMessage.toServiceNoticeDo(query).setUserId(userId);
        snd.setId(IdGenerator.id());
        serviceNoticeRepository.insert(snd);

        // 定时发布
        if (f)
            rabbitManager.sendDelayMsg(
                    NoticeMqConstant.NOTICE_RELEASE_EXCHANGE,
                    NoticeMqConstant.NOTICE_SERVICE_RELEASE_ROUTING,
                    snd.getId(),
                    Duration.between(LocalDateTime.now(), query.getReleaseTime()).getSeconds()
            );

    }

    @Override
    public void updateById(ServiceNoticeUpdateQuery query) {

        // 关联字段校验
        boolean f = ObjUtil.equal(query.getState(), NoticeState.ON) && ObjUtil.equal(query.getTimedRelease(), true);
        if (f) {
            AssertUtil.notNull(query.getReleaseTime(), CommonResultEnum.PARAM_ERROR);
            query.setTimedRelease(false);
        }

        // 通知存在
        AssertUtil.isTrue(
                serviceNoticeRepository.exist1Eq(
                        ServiceNoticeDo::getId, query.getId(), ServiceNoticeDo.class
                ),
                ServiceNoticeResultEnum.NOTICE_NOT_FOUND
        );

        // 更新
        ServiceNoticeDo snd = mapStructMessage.toServiceNoticeDo(query).setUserId(0L);
        serviceNoticeRepository.updateById(snd);

        // 定时发布
        rabbitManager.sendDelayMsg(
                NoticeMqConstant.NOTICE_RELEASE_EXCHANGE,
                NoticeMqConstant.NOTICE_SERVICE_RELEASE_ROUTING,
                snd.getId(),
                Duration.between(LocalDateTime.now(), query.getReleaseTime()).getSeconds()
        );

    }

    @Override
    public void deleteById(Long id) {
        AssertUtil.isTrue(
                serviceNoticeRepository.exist1Eq(
                        ServiceNoticeDo::getId, id, ServiceNoticeDo.class
                ),
                ServiceNoticeResultEnum.NOTICE_NOT_FOUND
        );
        serviceNoticeRepository.deleteById(id);
    }

    @Override
    public void changeState(Long id, NoticeState state) {
        AssertUtil.isTrue(
                serviceNoticeRepository.exist1Eq(
                        ServiceNoticeDo::getId, id, ServiceNoticeDo.class
                ),
                ServiceNoticeResultEnum.NOTICE_NOT_FOUND
        );
        serviceNoticeRepository.update1Set1Eq(
                ServiceNoticeDo::getState, NoticeState.ON,
                ServiceNoticeDo::getId, id,
                ServiceNoticeDo.class
        );
    }


    /**
     * 构建通知分页查询条件
     */
    private LambdaQueryWrapper<ServiceNoticeDo> buildPageQueryWrapper(ServiceNoticePageQuery query) {

        LambdaQueryWrapper<ServiceNoticeDo> w = Wrappers.lambdaQuery(ServiceNoticeDo.class);

        w.like(ObjUtil.notBlank(query.getTitle()), ServiceNoticeDo::getTitle, query.getTitle());

        w.like(ObjUtil.notBlank(query.getKeyword()), ServiceNoticeDo::getContent, query.getKeyword());

        w.like(ObjUtil.notBlank(query.getSignature()), ServiceNoticeDo::getSignature, query.getSignature());

        w.ge(query.getCreateTimeFrom() != null, ServiceNoticeDo::getCreateTime, query.getCreateTimeFrom());
        w.le(query.getCreateTimeTo() != null, ServiceNoticeDo::getCreateTime, query.getCreateTimeTo());

        w.orderBy(true, false, ServiceNoticeDo::getCreateTime);

        return w;
    }

}
